/**
  ******************************************************************************
  * @file    unpacker.c
  * @author  lzc
  * @version V1.0
  * @date
  * @brief   链路层通讯协议
  ******************************************************************************
  * @attention
  *          链路层通讯协议，数据封包解包 HEX协议解构
  ******************************************************************************
  */
#include "upacker.h"

static uint8_t frame_decode(upacker_inst_t packer, uint8_t d);
static uint8_t frame_encode(upacker_inst_t packer, uint16_t command, uint8_t *data, uint16_t size);

static char Frame_Len_Count = 0;
static char Frame_CMD_Count = 0;
static char Frame_Head_Check_Count = 0;
/**
 * @brief  使用动态内存时需要初始化
 * @note   size pack缓存的长度，大于最大的数据包长度就行,使用PACK_SIZE
            无rtos最好用静态内存,不然要改heap
 * @param  *cmd_packer:
 * @param  *handler:
 * @retval None
 */
int upacker_init(upacker_inst_t packer, PACKER_CB h, SEND_CB s)
{
#if USE_DYNAMIC_MEM
    packer->data = (uint8_t *)UP_MALLOC(MAX_PACK_SIZE);
    if (!packer->data)
    {
        return -1;
    }
#endif

    packer->cb = h;
    packer->send = s;
    return 0;
}

/**
 * @brief  解包输入数据
 * @note
 * @param  cmd_packer:
 * @param  *buff:
 * @param  size:
 * @retval None
 */
void upacker_unpack(upacker_inst_t packer, uint8_t *buff, uint16_t size)
{
    uint16_t i = 0;
#if UPACKER_DEBUG
    for ( i = 0; i < size; i++)
    {
        rt_kprintf("buff[%d]: %x\n", i, buff[i]);
    }
#endif
    for ( i = 0; i < size; i++)
    {
        if (frame_decode(packer, buff[i]))
        {
            //解析成功,回调处理
            packer->cb(packer->command, packer->data, packer->flen);
        }
    }
}

/**
 * @brief  清除旧数据
 * @note
 * @param  *packer:
 * @param  *buff:
 * @param  size:
 * @retval None
 */
static void upacker_clear_old_packers(upacker_inst_t packer)
{
    packer->cnt = 0;
    packer->calc = 0;
    packer->state = 0;
    packer->check = 0;
    packer->version = 0;

    // packer->command = 0;
    // packer->flen = 0;
    // memset(packer->data, 0, MAX_PACK_SIZE);
    Frame_Len_Count = 0;
    Frame_CMD_Count = 0;
    Frame_Head_Check_Count = 0;
}

/**
 * @brief  封包数据并发送
 * @note
 * @param  *packer:
 * @param  *buff:
 * @param  size:
 * @retval None
 */
void upacker_pack(upacker_inst_t packer, uint16_t command, uint8_t *buff, uint16_t size)
{
    frame_encode(packer, command, buff, size);
}

static uint8_t frame_decode(upacker_inst_t packer, uint8_t d)
{
    int i = 0;
    // DONE: 此处判断帧头
    if (packer->state == 0)
    {
        if (Frame_Head_Check_Count == 0 && d == STX_HEAD1)
            Frame_Head_Check_Count = 1;
        if (Frame_Head_Check_Count == 1 && d == STX_HEAD2)
        {
            Frame_Head_Check_Count = 0;
            packer->state = 1;
        }
    }
    // DONE: 此处获取版本
    else if (packer->state == 1)
    {
        packer->version = d;
        packer->state = 2;
#if UPACKER_DEBUG
        rt_kprintf("version is %x\n", packer->version);
#endif
    }
    // DONE: 此处判断幁长
    else if (packer->state == 2)
    {
        //长度信息获取
        if (Frame_Len_Count == 0)
        {
            packer->flen = d << 8;
            Frame_Len_Count = 1;
        }
        else
        {
            packer->flen += d ;
            Frame_Len_Count = 2;
        }
        //数据包超长得情况下直接丢包
        if ((packer->flen ) > MAX_PACK_SIZE)
        {
            packer->state = 0;
        }
        if (Frame_Len_Count == 2)
        {
            Frame_Len_Count = 0;
            packer->state = 3;
            packer->cnt = 0;
#if UPACKER_DEBUG
            rt_kprintf("lens is %x\n", packer->flen);
#endif
        }
    }
    // DONE: 指令获取
    else if (packer->state == 3)
    {
        if (Frame_CMD_Count == 0)
        {
            packer->command = d << 8;
            Frame_CMD_Count = 1;
        }
        else
        {
            packer->command += d ;
            Frame_CMD_Count = 2;
        }
        if (Frame_CMD_Count == 2)
        {
            Frame_CMD_Count = 0;
            packer->state = 4;
#if UPACKER_DEBUG
            rt_kprintf("command is %x\n", packer->command);
#endif
            packer->cnt = 0;
        }
    }
    // DONE: 数据获取
    else if (packer->state == 4)
    {
        // DONE: 此处判断数据长度是否到达最后
        if ( packer->flen - 3 > 0 && packer->cnt < packer->flen - 3)
        {
            packer->data[packer->cnt++] = d;
        }
        // 如果包内本来就没有数据
        else if ( packer->flen - 3 == 0)
        {
            packer->check = d;
#if UPACKER_DEBUG
            rt_kprintf("check is %x\n", packer->check);
#endif
            packer->calc += (packer->version + packer->flen + packer->command);
            packer->calc = packer->calc % 256;
            if (packer->calc == packer->check)
            {
                upacker_clear_old_packers(packer);
                return 1;
            }
            else
            {
                upacker_clear_old_packers(packer);
                return 0;
            }
        }
        // 接收数据完成
        if (packer->flen - 3 > 0 && packer->cnt == packer->flen - 3)
        {
            for ( i = 0; i < packer->flen - 3; i++)
            {
                packer->calc += packer->data[i];
#if UPACKER_DEBUG
                rt_kprintf("data[%d] is %x\n", i, packer->data[i]);
#endif
            }
            packer->state = 5;
        }
    }
    // DONE: 此处判断校验
    else if (packer->state == 5)
    {
        packer->check = d;
#if UPACKER_DEBUG
        rt_kprintf("check is %x\n", packer->check);
#endif
        //DONE: 接收完，检查check
        // 计算校验值的准确性
        packer->calc += (packer->version + packer->flen + packer->command);
        packer->calc = packer->calc % 256;
        if (packer->calc == packer->check)
        {
            upacker_clear_old_packers(packer);
            return 1;
        }
        else
        {
            upacker_clear_old_packers(packer);
            return 0;
        }
    }
    else
    {
        packer->state = 0;
    }
    return 0;
}

/**
 * @function: frame_encode
 * @brief:
 * @param {upacker_inst_t} packer
 * @param {uint16_t} command
 * @param {uint8_t} *data    Data
 * @param {uint16_t} size    Data 的Size
 * @return {*}
 * @author: lzc
 */
static uint8_t frame_encode(upacker_inst_t packer, uint16_t command, uint8_t *data, uint16_t size)
{
    uint8_t tmp[7] = {0};
    uint8_t check[1] = { 0 };
    uint16_t check_sum = 0;
    int i = 0;
    if (size > 16384)
    {
        return 0;
    }
    tmp[0] = STX_HEAD1;
    tmp[1] = STX_HEAD2;
    tmp[2] = 0x10;
    tmp[3] = ((size + 3) >> 8);   // command + check + Datalength (H)
    tmp[4] = ((size + 3) & 0xff); // command + check + Datalength (L)

    tmp[5] = command >> 8;
    tmp[6] = command & 0xff;

    packer->send( tmp, 7);
    packer->send( data, size);
    check_sum = tmp[2] + (size + 3) + command ;
    for (i = 0; i < size; i++)
        check_sum += data[i];
    check[0] = check_sum % 256;
    packer->send( check, 1);
    return 1;
}
